package com.leinao.file.service.impl;

import com.leinao.commons.Response;
import com.leinao.commons.ResponseMessage;
import com.leinao.config.EnvironmentConfig;
import com.leinao.constant.*;
import com.leinao.dataset.dao.PaiDataSetMapper;
import com.leinao.dataset.model.PaiDataSet;
import com.leinao.file.dto.FileFilePathDto;
import com.leinao.file.dto.FilePageDto;
import com.leinao.file.dto.FileProcessDataDto;
import com.leinao.file.dto.ProjectInfoDto;
import com.leinao.file.service.BusinessFileService;
import com.leinao.file.service.FileService;
import com.leinao.git.GitService;
import com.leinao.login.dto.LoginResultDto;
import com.leinao.project.dao.ProjectMapper;
import com.leinao.project.model.PaiProjectJob;
import com.leinao.project.model.Project;
import com.leinao.util.FileUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
public class BusinessFileServiceImpl implements BusinessFileService {

	private static final Logger LOGGER = LoggerFactory.getLogger(BusinessFileServiceImpl.class);

	@Autowired
	private ProjectMapper projectMapper;

	@Autowired
	private PaiDataSetMapper paiDataSetMapper;

	@Autowired
	private PaiDataSetMapper dataSetMapper;

	@Autowired
	private FileUtil fileUtil;

	@Autowired
	EnvironmentConfig env;

	@Autowired
	private FileService fileService;

	@Autowired
	private GitService gitService;

	/**
	 * @Description 项目创建仓库初始化
	 * @param projectName : 项目名称
	 * @param timestamp : 时间戳，可以用来保证代码仓库名唯一
	 * @param userInfo : 用户信息
	 * @author lizi
	 * @date 2018/12/19 下午3:12
	 */
	@Override
	public Response<String> initRepository(String projectName, String timestamp, LoginResultDto userInfo) {
		// 获取项目信息
		long start = System.currentTimeMillis();

		// 返回结果定义
		String projectPath = fileUtil.getBaseDir(userInfo.getUserId(), PathTypeEnum.PROJECT.getType()) + File.separator + projectName + Constant.PROJECT_CODE_STRUCTURE;
		Response<Void> response = fileUtil.addDir(projectPath);
		if(response.getMessage().getCode() != ResponseMessage.SUCCESS_CODE && response.getMessage().getCode() != FileErrorEnum.FILE_EXIST.getSeq()) {
			return Response.error(Constant.SUCCESS_CODE, response.getMessage().getCode(), response.getMessage().getMessage(),null);
		}

		Response<String> gitResponse = gitService.initRepository(userInfo.getUserId(), projectPath, projectName, timestamp);
		LOGGER.info("initRepository userId : {}, projectName : {}, spend time : {}s", userInfo.getUserId(), projectName, (System.currentTimeMillis()  - start) / 1000);
		return gitResponse;
	}

	/***
	 * @Description 拷贝公开项目代码到本地
	 * @param projectId : 项目ID
	 * @param projectName : 项目名称
	 * @param timestamp : 时间戳，可以用来保证代码仓库名唯一
	 * @param maxTag 最大任务标签
	 * @param tags 任务标签，多个逗号隔开
	 * @param userInfo : 用户信息
	 * @author lizi
	 * @date 2018/11/29 下午3:57
	 */
	@Override
	public Response<String> cloneRepository(Long projectId, String projectName, String timestamp, String maxTag, String tags, LoginResultDto userInfo) {
		// 获取项目信息
		long start = System.currentTimeMillis();
		Project project = projectMapper.getProject(projectId);
		if(project == null) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.INVALID_PROJECT_ID.getSeq(), FileErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}

		// 项目是否公开
		if(!ProjectTypeEnum.PUBLIC.getType().equals(project.getType())) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.PROJECT_NOT_PUBLIC.getSeq(), FileErrorEnum.PROJECT_NOT_PUBLIC.getDesc(), null);
		}

		// 返回结果定义
		String projectPath = project.getFilePath();
		if(StringUtils.isEmpty(projectPath)) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.PROJECT_NOT_CONTAINS_FILE.getSeq(), FileErrorEnum.PROJECT_NOT_CONTAINS_FILE.getDesc(), null);
		}

		// 克隆项目文件夹建立
		String copyTo = fileUtil.getBaseDir(userInfo.getUserId(), PathTypeEnum.PROJECT.getType()) + File.separator + projectName;
		Response<Void> copyResponse = fileUtil.addDir(copyTo);
		if(copyResponse.getMessage().getCode() != ResponseMessage.SUCCESS_CODE && copyResponse.getMessage().getCode() != FileErrorEnum.FILE_EXIST.getSeq()) {
			return Response.error(Constant.SUCCESS_CODE, copyResponse.getMessage().getCode(), copyResponse.getMessage().getMessage(),null);
		}

		// 调用gitService进行代码克隆和代码仓库重新初始化，并且返回新的仓库地址
		Response<String> response = gitService.cloneNewRepository(userInfo.getUserId(), copyTo + Constant.PROJECT_CODE_STRUCTURE, projectName,
				timestamp, project.getGitRepository(), maxTag, Arrays.asList(tags.split(",")));
		LOGGER.info("cloneRepository spend userId : {}, projectId : {}, time : {}s", userInfo.getUserId(), projectId, (System.currentTimeMillis()  - start) / 1000);
		return response;
	}

	/**
	 * @Description 提交任务打标签
	 * @param projectId : 项目ID
	 * @param tag 任务名
	 * @param userInfo : 用户信息
	 * @author lizi
	 * @date 2018/12/19 下午3:12
	 */
	@Override
	public Response<String> addTag(Long projectId, String tag, LoginResultDto userInfo) {
		// 获取项目信息
		long start = System.currentTimeMillis();
		Project project = projectMapper.getProject(projectId);
		if(project == null) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.INVALID_PROJECT_ID.getSeq(), FileErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}

		// 项目是否公开
		if(ProjectTypeEnum.PUBLIC.getType().equals(project.getType())) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.PROJECT_ALREADY_PUBLIC.getSeq(), FileErrorEnum.PROJECT_ALREADY_PUBLIC.getDesc(), null);
		}

		// 项目是否是自己的
		if(!project.getUserId().equals(userInfo.getUserId())) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.PROJECT_NO_AUTHORITY.getSeq(), FileErrorEnum.PROJECT_NO_AUTHORITY.getDesc(), null);
		}

		// 返回结果定义
		String projectPath = project.getFilePath();
		if(StringUtils.isEmpty(projectPath)) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.PROJECT_NOT_CONTAINS_FILE.getSeq(), FileErrorEnum.PROJECT_NOT_CONTAINS_FILE.getDesc(), null);
		}

		// 校验提交的代码文件大小
		long now = System.currentTimeMillis();
        List<Long> sizeList = new ArrayList<>();
        sizeList.add(0L);
        fileUtil.statisticalFolderSize(Paths.get(projectPath), sizeList, Constant.MAX_PROJECT_FILE_SIZE);
		LOGGER.info("addTag statisticalFolderSize projectPath : {}, fileSize : {}kB, spend time : {}s：", projectPath, (sizeList.get(0) / 1024), (System.currentTimeMillis()  - now) / 1000);
        if(sizeList.get(0) > Constant.MAX_PROJECT_FILE_SIZE) {
            return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.PROJECT_CODE_SIZE_OVER_LIMIT.getSeq(), FileErrorEnum.PROJECT_CODE_SIZE_OVER_LIMIT.getDesc(), null);
        }

		// 如果项目文件夹为空则初始化一个空文件
		now = System.currentTimeMillis();
		boolean initGitKeepFile = fileUtil.initGitKeepFile(projectPath);
		LOGGER.info("addTag initGitKeepFile projectPath : {}, spend time : {}s：", projectPath, (System.currentTimeMillis()  - now) / 1000);
		if(!initGitKeepFile) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.INIT_PROJECT_CODE_FAILURE.getSeq(), FileErrorEnum.INIT_PROJECT_CODE_FAILURE.getDesc(), null);
		}

		// 调用gitService进行代码添加标签
		Response<String> response = gitService.initTag(projectPath, tag);
		LOGGER.info("addTag spend userId : {}, projectId : {}, time : {}s", userInfo.getUserId(), projectId, (System.currentTimeMillis()  - start) / 1000);
		return response;
	}

	/**
	 * @Description 获取公开项目文件列表
	 * @param projectId : 项目ID
	 * @param dir 目录
	 * @param pageNumber 当前页
	 * @param pageSize 每业条数
	 * @author suqiliang
	 * @Date 2018年7月2日 上午11:28:35
	 */
	@Override
	public Response<FilePageDto> getPublicProjectFileList(Long projectId, String dir, Integer pageNumber, Integer pageSize) {
		LOGGER.debug("获取公开项目文件列表...");

		// 获取项目信息
		Project project = projectMapper.getProject(projectId);
		if(project == null) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.INVALID_PROJECT_ID.getSeq(), FileErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}

		// 项目是否公开
		if(!ProjectTypeEnum.PUBLIC.getType().equals(project.getType())) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.PROJECT_NOT_PUBLIC.getSeq(), FileErrorEnum.PROJECT_NOT_PUBLIC.getDesc(), null);
		}

		// 获取项目代码
		return getGitFileList(project, dir, pageNumber, pageSize);
	}

	/**
	 * @Description 获取公开任务文件列表
	 * @param projectPublicJobId : 公开任务ID
	 * @param dir 目录
	 * @param pageNumber 当前页
	 * @param pageSize 每业条数
	 * @author suqiliang
	 * @Date 2018年7月2日 上午11:28:35
	 */
	@Override
	public Response<FilePageDto> getProjectPublicJobFileList(Long projectPublicJobId, String dir, Integer pageNumber, Integer pageSize) {
		LOGGER.debug("获取公开任务文件列表...");

		// 获取公开任务信息
		PaiProjectJob projectJob = projectMapper.getProjectPublicJobInfoByJobId(projectPublicJobId);
		if(projectJob == null) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.INVALID_PROJECT_PUBLIC_JOB_ID.getSeq(), FileErrorEnum.INVALID_PROJECT_PUBLIC_JOB_ID.getDesc(), null);
		}

		// 获取项目信息
		Project project = projectMapper.getProject(projectJob.getProjectId());

		// 获取任务代码
		project.setGitTag(projectJob.getGitTag());
		project.setUpdateTime(projectJob.getCreateTime());
		return getGitFileList(project, dir, pageNumber, pageSize);
	}

	/**
	 * @Description 获取个人项目文件列表
	 * @param projectJobId : 个人任务ID
	 * @param dir 目录
	 * @param pageNumber 当前页
	 * @param pageSize 每业条数
	 * @param userInfo : 用户信息
	 * @author suqiliang
	 * @Date 2018年7月2日 上午11:28:35
	 */
	@Override
	public Response<FilePageDto> getProjectJobFileList(Long projectJobId, String dir, Integer pageNumber, Integer pageSize, LoginResultDto userInfo) {
		LOGGER.debug("获取个人任务文件列表...");

		// 获取个人任务信息
		PaiProjectJob projectJob = projectMapper.getProjectJobInfoByJobId(projectJobId);
		if(projectJob == null) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.INVALID_PROJECT_JOB_ID.getSeq(), FileErrorEnum.INVALID_PROJECT_JOB_ID.getDesc(), null);
		}

		// 获取项目信息
		Project project = projectMapper.getProject(projectJob.getProjectId());
		if(!project.getUserId().equals(userInfo.getUserId())) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.PROJECT_NO_AUTHORITY.getSeq(), FileErrorEnum.PROJECT_NO_AUTHORITY.getDesc(), null);
		}

        // 获取任务代码
        project.setGitTag(projectJob.getGitTag());
        project.setUpdateTime(projectJob.getCreateTime());
        return getGitFileList(project, dir, pageNumber, pageSize);
	}

	/**
	 * @Description 获取公开数据集文件列表
	 * @param userId  用户id
	 * @param number : 数据集编号
	 * @author suqiliang
	 * @Date 2018年12月18日 下午5:28:35
	 */
	@Override
	public Response<FilePageDto> getPublicDatasetFileList(String userId, String number) {
		LOGGER.debug("获取公开数据集文件列表...");

		// 获取项目信息
		PaiDataSet dataSet = paiDataSetMapper.getDataSetDetailByNumber(number, userId);
		if(dataSet == null) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.INVALID_DATASET_NUMBER.getSeq(), FileErrorEnum.INVALID_DATASET_NUMBER.getDesc(), null);
		}

		// 获取数据集代码路径
		String path = dataSet.getPath();
		if(StringUtils.isEmpty(path)) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.DATASET_NOT_CONTAINS_FILE.getSeq(), FileErrorEnum.DATASET_NOT_CONTAINS_FILE.getDesc(), null);
		}

		// 此处固定只查看根目录前10条目录或文件
		return fileUtil.getFileList(path, 1, 10);
	}

	/**
	 * @Description 公开文件预览
	 * @param projectId : 项目ID
	 * @param dir : 文件路径
	 * @param response response对象
	 * @author lizi
	 * @date 2018/12/18 下午5:57
	 */
	@Override
	public void previewPublicProjectFile(Long projectId, String dir, HttpServletResponse response) {
		// 获取项目信息
		Project project = projectMapper.getProject(projectId);
		if(project == null) {
			LOGGER.info("previewPublicProjectFile project is null, param projectId : {}", projectId);
			return;
		}

		// 项目是否公开
		if(!ProjectTypeEnum.PUBLIC.getType().equals(project.getType())) {
			LOGGER.info("previewPublicProjectFile project is not public, param projectId : {}", projectId);
			return;
		}

		// 获取项目代码路径
		String gitRepository = project.getGitRepository();
		String gitTag = project.getGitTag();
		if(StringUtils.isEmpty(gitRepository) || StringUtils.isEmpty(gitTag)) {
			LOGGER.info("previewPublicProjectFile project  is empty, param gitRepository : {}, gitTag : {}", gitRepository, gitTag);
			return;
		}

		// 文件预览
        if(Files.exists(Paths.get(project.getFilePath()))) {
            gitService.previewLocalFile(project.getFilePath(), project.getGitTag(), dir, response);
        } else {
            gitService.previewRemoteFile(gitRepository, project.getGitTag(), dir, response);
        }
	}

	/**
	 * @Description 公开任务文件预览
	 * @param projectPublicJobId : 公开任务ID
	 * @param dir : 文件路径
	 * @param response response对象
	 * @author lizi
	 * @date 2018/12/18 下午5:57
	 */
	@Override
	public void previewPublicProjectJobFile(Long projectPublicJobId, String dir, HttpServletResponse response) {
		LOGGER.debug("获取公开任务文件列表...");

		// 获取公开任务信息
		PaiProjectJob projectJob = projectMapper.getProjectPublicJobInfoByJobId(projectPublicJobId);
		if(projectJob == null) {
			LOGGER.info("previewPublicProjectJobFile job not exist, param projectPublicJobId : {}", projectPublicJobId);
			return;
		}

		// 获取项目信息
		Project project = projectMapper.getProject(projectJob.getProjectId());

		// 获取项目代码路径
		String gitRepository = project.getGitRepository();
		String gitTag = projectJob.getGitTag();
		if(StringUtils.isEmpty(gitRepository) || StringUtils.isEmpty(gitTag)) {
			LOGGER.info("previewPublicProjectJobFile project  is empty, param gitRepository : {}, gitTag : {}", gitRepository, gitTag);
			return;
		}

		// 文件预览
        if(Files.exists(Paths.get(project.getFilePath()))) {
		    gitService.previewLocalFile(project.getFilePath(), gitTag, dir, response);
        } else {
            gitService.previewRemoteFile(gitRepository, gitTag, dir, response);
        }
	}

	/**
	 * @Description 公开任务文件预览
	 * @param projectJobId : 任务ID
	 * @param dir : 文件路径
	 * @param userInfo : 用户信息
	 * @param response response对象
	 * @author lizi
	 * @date 2018/12/18 下午5:57
	 */
	@Override
	public void previewProjectJobFile(Long projectJobId, String dir, LoginResultDto userInfo, HttpServletResponse response) {
		LOGGER.debug("获取个人任务文件列表...");

		// 获取个人任务信息
		PaiProjectJob projectJob = projectMapper.getProjectJobInfoByJobId(projectJobId);
		if(projectJob == null) {
			LOGGER.info("previewProjectJobFile job not exist, param projectJobId : {}", projectJobId);
			return;
		}

		// 获取项目信息
		Project project = projectMapper.getProject(projectJob.getProjectId());
		if(!project.getUserId().equals(userInfo.getUserId())) {
			LOGGER.info("previewProjectJobFile no authority, param projectJobId : {}, userId : {}", projectJobId, userInfo.getUserId());
			return;
		}

		// 获取项目代码路径
		String gitRepository = project.getGitRepository();
		String gitTag = projectJob.getGitTag();
		if(StringUtils.isEmpty(gitRepository) || StringUtils.isEmpty(gitTag)) {
			LOGGER.info("previewProjectJobFile project  is empty, param gitRepository : {}, gitTag : {}", gitRepository, gitTag);
			return;
		}

		// 文件预览
        if(Files.exists(Paths.get(project.getFilePath()))) {
            gitService.previewLocalFile(project.getFilePath(), gitTag, dir, response);
        } else {
            gitService.previewRemoteFile(gitRepository, gitTag, dir, response);
        }
	}

	/**
	 * @Description 公开项目远程仓库文件下载 支持批量下载
	 * @param projectId : 公开项目ID
	 * @param dirs : 下载路径
	 * @param response response对象
	 * @author lizi
	 * @date 2018/11/19 下午9:07
	 */
	@Override
	public void downloadPublicProjectFile(Long projectId, String[] dirs, HttpServletResponse response) {
		try {
			response.setContentType("application/json; charset=utf-8");
			response.setContentType("application/octet-stream");
			OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());

			// 获取项目信息
			Project project = projectMapper.getProject(projectId);
			if(project == null) {
				LOGGER.info("downLoadPublicProjectFile project is null, param projectId : {}", projectId);
				return;
			}

			// 项目是否公开
			if(!ProjectTypeEnum.PUBLIC.getType().equals(project.getType())) {
				LOGGER.info("downLoadPublicProjectFile project is not public, param projectId : {}", projectId);
				return;
			}

			// 获取项目代码路径
			String gitRepository = project.getGitRepository();
			String gitTag = project.getGitTag();
			if(StringUtils.isEmpty(gitRepository) || StringUtils.isEmpty(gitTag)) {
				LOGGER.info("downLoadPublicProjectFile project  is empty, param gitRepository : {}, gitTag : {}", gitRepository, gitTag);
				return;
			}

			// 下载程仓库文件
            if(Files.exists(Paths.get(project.getFilePath()))) {
                downloadLocalFile(project.getFilePath() ,gitTag, dirs, outputStream ,response);
            } else {
                downloadRemoteFile(gitRepository ,gitTag, dirs, outputStream ,response);
            }

			outputStream.flush();
			outputStream.close();
		} catch (UnsupportedEncodingException e) {
			LOGGER.error("downLoadPublicProjectFile UnsupportedEncodingException", e);
		} catch (IOException e) {
			LOGGER.error("downLoadPublicProjectFile IOException", e);
		}
	}

	/**
	 * @Description 公开任务远程仓库文件下载 支持批量下载
	 * @param projectPublicJobId : 公开任务ID
	 * @param dirs : 下载路径
	 * @param response response对象
	 * @author lizi
	 * @date 2018/11/19 下午9:07
	 */
	@Override
	public void downloadPublicProjectJobFile(Long projectPublicJobId, String[] dirs, HttpServletResponse response) {
		try {
			response.setContentType("application/json; charset=utf-8");
			response.setContentType("application/octet-stream");
			OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());

			// 获取公开任务信息
			PaiProjectJob projectJob = projectMapper.getProjectPublicJobInfoByJobId(projectPublicJobId);
			if(projectJob == null) {
				LOGGER.info("previewPublicProjectJobFile job not exist, param projectPublicJobId : {}", projectPublicJobId);
				return;
			}

			// 获取项目信息
			Project project = projectMapper.getProject(projectJob.getProjectId());

			// 获取项目代码路径
			String gitRepository = project.getGitRepository();
			String gitTag = projectJob.getGitTag();
			if(StringUtils.isEmpty(gitRepository) || StringUtils.isEmpty(gitTag)) {
				LOGGER.info("previewPublicProjectJobFile project  is empty, param gitRepository : {}, gitTag : {}", gitRepository, gitTag);
				return;
			}

			// 下载程仓库文件
            if(Files.exists(Paths.get(project.getFilePath()))) {
                downloadLocalFile(project.getFilePath() ,gitTag, dirs, outputStream ,response);
            } else {
                downloadRemoteFile(gitRepository ,gitTag, dirs, outputStream ,response);
            }

			outputStream.flush();
			outputStream.close();
		} catch (UnsupportedEncodingException e) {
			LOGGER.error("downLoadPublicProjectJobFile UnsupportedEncodingException", e);
		} catch (IOException e) {
			LOGGER.error("downLoadPublicProjectJobFile IOException", e);
		}
	}

	/**
	 * @Description 公开项目远程仓库文件下载 支持批量下载
	 * @param projectJobId : 任务ID
	 * @param dirs : 下载路径
	 * @param userInfo : 用户信息
	 * @param response response对象
	 * @author lizi
	 * @date 2018/11/19 下午9:07
	 */
	@Override
	public void downloadProjectJobFile(Long projectJobId, String[] dirs, LoginResultDto userInfo, HttpServletResponse response) {
		try {
			response.setContentType("application/json; charset=utf-8");
			response.setContentType("application/octet-stream");
			OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());

			// 获取个人任务信息
			PaiProjectJob projectJob = projectMapper.getProjectJobInfoByJobId(projectJobId);
			if(projectJob == null) {
				LOGGER.info("downloadProjectJobFile job not exist, param projectJobId : {}", projectJobId);
				return;
			}

			// 获取项目信息
			Project project = projectMapper.getProject(projectJob.getProjectId());
			if(!project.getUserId().equals(userInfo.getUserId())) {
				LOGGER.info("downloadProjectJobFile no authority, param projectJobId : {}, userId : {}", projectJobId, userInfo.getUserId());
				return;
			}

			// 获取项目代码路径
			String gitRepository = project.getGitRepository();
			String gitTag = projectJob.getGitTag();
			if(StringUtils.isEmpty(gitRepository) || StringUtils.isEmpty(gitTag)) {
				LOGGER.info("downloadProjectJobFile project  is empty, param gitRepository : {}, gitTag : {}", gitRepository, gitTag);
				return;
			}

			// 下载程仓库文件
            if(Files.exists(Paths.get(project.getFilePath()))) {
                downloadLocalFile(project.getFilePath(), gitTag, dirs, outputStream, response);
            } else {
                downloadRemoteFile(gitRepository ,gitTag, dirs, outputStream ,response);
            }

			outputStream.flush();
			outputStream.close();
		} catch (UnsupportedEncodingException e) {
			LOGGER.error("downloadProjectJobFile UnsupportedEncodingException", e);
		} catch (IOException e) {
			LOGGER.error("downloadProjectJobFile IOException", e);
		}
	}

	/**
	 * @Description 公开数据集文件预览
	 * @param userId : 用户ID
	 * @param number : 数据集编号
	 * @param filePath : 文件路径
	 * @param response : response对象 
	 * @author lizi
	 * @date 2019/03/19 下午5:33
	 */
	@Override
	public void previewPublicDatasetFile(String userId, String number, String filePath, HttpServletResponse response) {
		// 获取数据集信息
		PaiDataSet dataSet = paiDataSetMapper.getDataSetDetailByNumber(number, userId);
		if(dataSet == null) {
			LOGGER.info("previewPublicDatasetFile dataset is null...");
			return;
		}

		// 获取数据集代码路径
		String path = dataSet.getPath();
		if(StringUtils.isEmpty(path)) {
			LOGGER.info("previewPublicDatasetFile dataset path is empty...");
			return;
		}

		// 文件预览
		fileService.previewFile(path + filePath, response);
	}

    /**
     * @Description 创建任务输出目录
     * @param userId : 用户ID
     * @param projectId : 项目ID
     * @param jobNumber : 任务编号
     * @author lizi
     * @date 2019/03/25 下午5:33
     */
    @Override
    public Response<String> createJobOutputs(String userId, Long projectId, Integer jobNumber) {
        // 获取项目信息
        Project project = projectMapper.getProject(projectId);
        if(project == null) {
            return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.INVALID_PROJECT_ID.getSeq(), FileErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
        }

        // 验证是否是自己的项目
        if(!project.getUserId().equals(userId)) {
            return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.PROJECT_NO_AUTHORITY.getSeq(), FileErrorEnum.PROJECT_NO_AUTHORITY.getDesc(), null);
        }

        // 项目代码复制
        String outputsDir = File.separator + project.getProjectName() + Constant.TASK_OUTPUTS_STRUCTURE + File.separator + jobNumber;
        String baseDir = fileUtil.getBaseDir(userId, PathTypeEnum.BASE.getType());
        Response<Void> response = fileUtil.addDir(baseDir + outputsDir);
        if(response.getMessage().getCode() == ResponseMessage.SUCCESS_CODE || response.getMessage().getCode() == FileErrorEnum.FILE_EXIST.getSeq()) {
            return Response.ok(baseDir + outputsDir);
        } else {
            return Response.error(Constant.SUCCESS_CODE, response.getMessage().getCode() , response.getMessage().getMessage(), null);
        }
    }

	/**
	 * @Description 创建目录，并复制文件
	 * @param projectId	项目Id
	 * @param jobName	任务名称
	 * @param dir		目录名称
	 * @param userInfo		用户信息
	 * @return
	 * @author:    weiwei
	 * @Date:  2019/5/20 13:41
	 */
	@Override
	public Response<Void> copyOutputFile(Long projectId, String jobName, String dir, LoginResultDto userInfo) {

		LOGGER.debug("copyOutputFile  文件复制...");
		FileFilePathDto codeNoAndFilePath = dataSetMapper.getCodeNoAndFilePath(jobName);
		String output = "/projects/"+ userInfo.getUserId() +"/"+ codeNoAndFilePath.getProjectName() +"/outputs/"+ codeNoAndFilePath.getCodeNo();
		LOGGER.info("copyOutputFile output: " +  output);

		LOGGER.debug("创建文件夹...");
		String copyToDri = env.getDatasetPath() + userInfo.getUserId() + dir;
		LOGGER.info("copyOutputFile copyToDri: " + copyToDri);

		Response<Void> responseAddDir = fileUtil.addDir(copyToDri);
		if(ResponseMessage.SUCCESS_CODE != responseAddDir.getMessage().getCode()) {
			return Response.ok(Constant.SUCCESS_CODE,
					DataSetErrorEnum.MAKE_OUTPUT_DIR_FAIL_ERROR.getSeq(), DataSetErrorEnum.MAKE_OUTPUT_DIR_FAIL_ERROR.getDesc(), null);
		}

		Response<String> response = fileUtil.copyOutputFile(output, copyToDri);
		// 存在文件夹或者文件复制失败，则立即返回
		if(ResponseMessage.SUCCESS_CODE != response.getMessage().getCode()) {
			return Response.ok(Constant.SUCCESS_CODE,
					DataSetErrorEnum.COPY_OUTPUT_FAIL_ERROR.getSeq(), DataSetErrorEnum.COPY_OUTPUT_FAIL_ERROR.getDesc(), null);
		}

		return Response.ok();
	}

	/**
	 * 功能描述: 获取项目-任务的输出output目录
	 * @param userId 用户ID
	 * @param projectId 项目ID
	 * @param jobName 任务名
	 * @param dir 项目路径
	 * @param pageNumber 当前页
	 * @param pageSize 每页条数
	 * @return com.leinao.commons.Response<com.leinao.file.dto.FilePageDto> 分页文件信息
	 * @Author: guoliangbo
	 * @Date: 2019/5/20 17:47
	 */
	@Override
	public Response<FilePageDto> getJobOutPutFileList(String userId, Long projectId, String jobName, String dir, Integer pageNumber, Integer pageSize) {

		//1.校验任务是否该用户的任务
		ProjectInfoDto project =  projectMapper.getProjectJobByParams(projectId,jobName);
		if( null == project ){
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectResultEnum.JOB_NOT_EXIST.getSeq(),ProjectResultEnum.JOB_NOT_EXIST.getDesc(),null);
		}
		if( !userId.equals(project.getUserId())){
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS,ProjectResultEnum.USER_HAS_NO_POWER.getSeq(),ProjectResultEnum.USER_HAS_NO_POWER.getDesc(),null);
		}
		String filePath = project.getFilePath();
		//2.拼接访问路径
		dir = filePath.substring(0,filePath.lastIndexOf("/")+1) + "outputs/"+ project.getCodeNo() + dir;
		return fileUtil.getFileList( dir, pageNumber, pageSize);
	}

	/**
	 * 功能描述： 下载outputs中的文件
	 * @param userId 用户id
	 * @param projectId 项目id
	 * @param jobName 任务名
	 * @param dirs 下载路径
	 * @param response respose
	 * @Return:void
	 * @Author: Guo Liangbo
	 * @Date:2019/5/20 21:27
	 */
	@Override
	public void jobOutputFileDownload(String userId, Long projectId, String jobName, String[] dirs, HttpServletResponse response) {
		try {
			response.setContentType("application/json; charset=utf-8");
			response.setContentType("application/octet-stream");
			OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());

			// 文件处理中间数据，如带宽
			FileProcessDataDto fileProcessData = new FileProcessDataDto();
			//查询项目信息
			//1.校验任务是否该用户的任务
			ProjectInfoDto project =  projectMapper.getProjectJobByParams(projectId,jobName);
			if( null == project ){
				return ;
			}
			if( !userId.equals(project.getUserId())){
				return ;
			}
			String filePath = project.getFilePath();
			String baseDir = filePath.substring(0,filePath.lastIndexOf("/")+1) + "outputs/"+ project.getCodeNo();
			String firstDir = dirs[0];
			// 单个文件下载
			if(dirs.length == 1 && !(Files.isDirectory(Paths.get(baseDir + firstDir)))) {
				String downloadFileName = java.net.URLEncoder.encode(Paths.get(firstDir).getFileName().toString(), Constant.DEFAULT_CHARSET);
				// 通知浏览器以下载的方式打开
				response.addHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
				fileUtil.downloadFile(baseDir + firstDir, outputStream, fileProcessData);
			} else {
				// 批量文件下载, 生成zip名称
				String downloadFileName = System.currentTimeMillis() +".zip";
				// 通知浏览器以下载的方式打开
				response.addHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
				fileUtil.batchDownloadFile(dirs, baseDir, outputStream, fileProcessData);
			}

			outputStream.flush();
			outputStream.close();
		} catch (UnsupportedEncodingException e) {
			LOGGER.error("downLoad UnsupportedEncodingException", e);
		} catch (IOException e) {
			LOGGER.error("downLoad IOException", e);
		}
	}

	/**
	 * 功能描述: 获取公开项目-任务的输出output目录
	 * @param userId 用户ID
	 * @param projectId 项目ID
	 * @param jobName 任务名
	 * @param dir 项目路径
	 * @param pageNumber 当前页
	 * @param pageSize 每页条数
	 * @return com.leinao.commons.Response<com.leinao.file.dto.FilePageDto> 分页文件信息
	 * @Author: guoliangbo
	 * @Date: 2019/5/20 17:47
	 */
	@Override
	public Response<FilePageDto> getPublicJobOutPutFileList(String userId, Long projectId, String jobName, String dir, Integer pageNumber, Integer pageSize) {

		//1.校验任务是否该用户的任务
		ProjectInfoDto project =  projectMapper.getPublicProjectJobByParams(projectId,jobName);
		if( null == project ){
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectResultEnum.JOB_NOT_EXIST.getSeq(),ProjectResultEnum.JOB_NOT_EXIST.getDesc(),null);
		}
		String filePath = project.getFilePath();
		//2.拼接访问路径
		dir = filePath.substring(0,filePath.lastIndexOf("/")+1) + "outputs/"+ project.getCodeNo() + dir;
		return fileUtil.getFileList( dir, pageNumber, pageSize);
	}

	@Override
	public void previewJobOutputFile(Long projectId, String jobName, String dir, HttpServletResponse response) {

		//1.校验任务是否该用户的任务
		ProjectInfoDto project =  projectMapper.getProjectJobByParams(projectId,jobName);
		if( null == project ){
			return ;
		}
		String filePath = project.getFilePath();
		//2.拼接访问路径
		dir = filePath.substring(0,filePath.lastIndexOf("/")+1) + "outputs/"+ project.getCodeNo() + dir;
		fileService.previewFile(dir,response);
	}

	@Override
	public void previewPublicJobOutputFile(Long projectId, String jobName, String dir, HttpServletResponse response) {

		//1.校验任务是否该用户的任务
		ProjectInfoDto project =  projectMapper.getPublicProjectJobByParams(projectId,jobName);
		if( null == project ){
			return ;
		}
		String filePath = project.getFilePath();
		//2.拼接访问路径
		dir = filePath.substring(0,filePath.lastIndexOf("/")+1) + "outputs/"+ project.getCodeNo() + dir;
		fileService.previewFile(dir, response);
	}

	/**
	 * @Description 获取Git服务器文件列表
	 * @param project : 项目信息
	 * @param dir 目录
	 * @param pageNumber 当前页
	 * @param pageSize 每业条数
	 * @author suqiliang
	 * @Date 2018年7月2日 上午11:28:35
	 */
	private Response<FilePageDto> getGitFileList(Project project, String dir, Integer pageNumber, Integer pageSize) {
		// 获取项目代码路径
		String projectPath = project.getFilePath();
		String gitRepository = project.getGitRepository();
		String gitTag = project.getGitTag();
		if(StringUtils.isEmpty(projectPath) || StringUtils.isEmpty(gitRepository) || StringUtils.isEmpty(gitTag)) {
			return Response.error(Constant.SUCCESS_CODE, FileErrorEnum.PROJECT_NOT_CONTAINS_FILE.getSeq(), FileErrorEnum.PROJECT_NOT_CONTAINS_FILE.getDesc(), null);
		}


        FilePageDto filePageDto = null;
        if(Files.exists(Paths.get(projectPath))) {
            // 获取本地仓库某个标签文件列表
            filePageDto = gitService.getLocalFileList(projectPath, gitTag, dir, pageNumber, pageSize);
        } else {
            // 获取远程仓库某个标签文件列表
            filePageDto = gitService.getRemoteFileList(gitRepository, gitTag, dir, pageNumber, pageSize);
        }

		// 由于git无法获取文件修改时间，将文件修改时间初始化为项目公开时间
		filePageDto.getFileList().forEach(fileInfoDto -> fileInfoDto.setUpdateTime(project.getUpdateTime()));

		return Response.ok(filePageDto);
	}

	/**
	 * @Description 下载远程程仓库文件
	 * @param repository 远程仓库地址 git@github.com:${userId}/project1-123123423423423.git
	 * @param tagName 标签名
	 * @param dirs 搜索路径，空字符串表示树的根
	 * @author lizi
	 * @date 2018/12/18 下午6:43
	 */
	private void downloadRemoteFile(String repository, String tagName, String[] dirs, OutputStream outputStream, HttpServletResponse response) throws UnsupportedEncodingException {
		// 单个文件下载
		if(dirs.length == 1 && !gitService.isRemoteDirectory(repository, tagName, dirs[0])) {
			// 文件名需要编码，否则文件名叫 "新建文本文档.txt"，其实是含有文字 "本" 就会下载失败，很神奇吧
			String downloadFileName = java.net.URLEncoder.encode(Paths.get(dirs[0]).getFileName().toString(), Constant.DEFAULT_CHARSET);
			// 通知浏览器以下载的方式打开
			response.addHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
			gitService.downloadRemoteFile(repository, tagName, dirs[0], outputStream);
		} else {
			// 批量文件下载, 生成zip名称
			String downloadFileName = System.currentTimeMillis() +".zip";
			// 通知浏览器以下载的方式打开
			response.addHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
			gitService.batchDownloadRemoteFile(repository, tagName, dirs, outputStream);
		}
	}

    /**
     * @Description 下载本地程仓库文件
     * @param localPath /projects/${userId}/${projectName}/code
     * @param tagName 标签名
     * @param dirs 搜索路径，空字符串表示树的根
     * @author lizi
     * @date 2018/12/18 下午6:43
     */
    private void downloadLocalFile(String localPath, String tagName, String[] dirs, OutputStream outputStream, HttpServletResponse response) throws UnsupportedEncodingException {
        // 单个文件下载
        if(dirs.length == 1 && !gitService.isLocalDirectory(localPath, tagName, dirs[0])) {
            // 文件名需要编码，否则文件名叫 "新建文本文档.txt"，其实是含有文字 "本" 就会下载失败，很神奇吧
            String downloadFileName = java.net.URLEncoder.encode(Paths.get(dirs[0]).getFileName().toString(), Constant.DEFAULT_CHARSET);
            // 通知浏览器以下载的方式打开
            response.addHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
            gitService.downloadLocalFile(localPath, tagName, dirs[0], outputStream);
        } else {
            // 批量文件下载, 生成zip名称
            String downloadFileName = System.currentTimeMillis() +".zip";
            // 通知浏览器以下载的方式打开
            response.addHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
            gitService.batchDownloadLocalFile(localPath, tagName, dirs, outputStream);
        }
    }

    /**
      * 功能描述: 模型所需复制output目录
      * @param projectName
      * @param codeNo
      * @param userId
      * @param modelName
      * @Return:com.leinao.commons.Response<java.lang.Void>
      * @Author:HuoPengfei
      * @Date:2019/6/5 14:53
      */
	@Override
	public Response<Void> copyOutputFileForModel(String projectName, Integer codeNo, String userId,String modelName) {
		LOGGER.debug("创建文件夹...");
		String prodir = "/projects/"+userId+"/"+projectName+"/outputs/"+codeNo;
        LOGGER.info("copyOutputFile copyToDri: " + prodir);
		//String prodir = "D:/20190605";
		String modeldir = "/models/"+userId+"/"+modelName;
		//String modeldir = "D:/20190605copy";
		Response<Void> responseAddDir = fileUtil.addDir(modeldir);
		if(ResponseMessage.SUCCESS_CODE != responseAddDir.getMessage().getCode()) {
			return Response.ok(Constant.SUCCESS_CODE,
					DataSetErrorEnum.MAKE_OUTPUT_DIR_FAIL_ERROR.getSeq(), DataSetErrorEnum.MAKE_OUTPUT_DIR_FAIL_ERROR.getDesc(), null);
		}
		LOGGER.info("copyOutputFile copyToDri: " + modeldir);
		Response<String> response = fileUtil.copyOutputFile(prodir, modeldir);
		// 存在文件夹或者文件复制失败，则立即返回
		if(ResponseMessage.SUCCESS_CODE != response.getMessage().getCode()) {
			return Response.ok(Constant.SUCCESS_CODE,
					DataSetErrorEnum.COPY_OUTPUT_FAIL_ERROR.getSeq(), DataSetErrorEnum.COPY_OUTPUT_FAIL_ERROR.getDesc(), null);
		}
		return Response.ok();
	}

	/**
	  * @Description 获取1.0用户文件列表
	  * @param userInfo
	  * @param pageNumber
	  * @param pageSize
	  * @return
	  * @author:    weiwei
	  * @Date:  2019/6/21 18:54
	  */
	@Override
	public Response<FilePageDto> getUserHomeFileList(LoginResultDto userInfo, Integer pageNumber, Integer pageSize) {

		LOGGER.debug("获取1.0userhome文件列表...");
		String path = Constant.USER_HOME_PREFIX + userInfo.getUserId();
//		String path = "C:/Users/Dell/Desktop/AAAA";
		return fileUtil.getFileList(path, pageNumber, pageSize);
	}

	/**
	  * @Description 复制文件到数据集/模型文件夹下
	  * @param userInfo
	  * @param dirs
	  * @param type
	  * @param targetDir
	  * @return
	  * @author:    weiwei
	  * @Date:  2019/6/24 13:12
	  */
    @Override
    public Response<String> copyFilesToDataSetOrModel(LoginResultDto userInfo, String[] dirs, Integer type, String targetDir) {

        // 循环复制
        String baseFrom = fileUtil.getBaseDir(userInfo.getUserId(), PathTypeEnum.BASE.getType());
		LOGGER.info("copyFilesToDataSetOrModel baseFrom: -----------------------------------------------------" + baseFrom);

		String dirTo = "";
        if(type.equals(Constant.DATASET_TYPE)){
            dirTo = fileUtil.getBaseDir(userInfo.getUserId(), PathTypeEnum.DATASET.getType());
        }else if(type.equals(Constant.MODEL_TYPE)){
            dirTo = fileUtil.getBaseDir(userInfo.getUserId(), PathTypeEnum.MODELS.getType());
        }

        for(String dir : dirs) {
			String copyFrom =  baseFrom;
			String copyTo = dirTo + targetDir;
//			String copyFrom = "F:" + baseFrom;
//			String copyTo = "F:" + dirTo + targetDir;

			if(dir.startsWith("/")){
				copyFrom = copyFrom + dir;
				LOGGER.info("copyFilesToDataSetOrModel copyFrom: -----------------------------------------------------" + copyFrom);
				copyTo = copyTo + dir;
				LOGGER.info("copyFilesToDataSetOrModel dirTo: -----------------------------------------------------" + copyTo);
				Response<Void> responseAddDir = fileUtil.addDir(copyTo);
				if(FileErrorEnum.FILE_CREATE_FAILURE.getSeq() == responseAddDir.getMessage().getCode()) {
					return Response.error(Constant.SUCCESS_CODE,
							FileErrorEnum.FILE_CREATE_FAILURE.getSeq(), FileErrorEnum.FILE_CREATE_FAILURE.getDesc(), null);
				}else if(FileErrorEnum.FILE_ACCESS_DENIED.getSeq() == responseAddDir.getMessage().getCode()) {
					return Response.error(Constant.SUCCESS_CODE,
							FileErrorEnum.FILE_ACCESS_DENIED.getSeq(), FileErrorEnum.FILE_ACCESS_DENIED.getDesc(), null);
				}else if(FileErrorEnum.FILE_EXIST.getSeq() == responseAddDir.getMessage().getCode()) {
					return Response.error(Constant.SUCCESS_CODE,
							FileErrorEnum.FILE_EXIST.getSeq(), FileErrorEnum.FILE_EXIST.getDesc(), null);
				}
				Response<String> response = fileUtil.copyOutputFile(copyFrom, copyTo);
				if(ResponseMessage.SUCCESS_CODE != response.getMessage().getCode()) {
					return response;
				}
			}else {
				copyFrom = copyFrom + "/" + dir;
				LOGGER.info("copyFilesToDataSetOrModel copyFrom: -----------------------------------------------------" + copyFrom);
				copyTo = copyTo + "/" + dir;
				LOGGER.info("copyFilesToDataSetOrModel dirTo: -----------------------------------------------------" + copyTo);

				Response<String> response = fileUtil.copyFile(copyFrom, copyTo);
				if(ResponseMessage.SUCCESS_CODE != response.getMessage().getCode()) {
					return response;
				}
			}

        }
        return Response.ok("ok");
    }
}
